/*
    Android UIML

	Copyright (C) 2010  Bram Goffings (bramgoffings@gmail.com)

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public License
	as published by the Free Software Foundation; either version 2.1
	of	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

package uiml.android.elements;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.view.View;

import uiml.android.RenderTools.RenderUtils;
import uiml.android.elements.peers.Vocabulary;
import uiml.android.executing.Call;

public class Property extends UimlElementWithAttributes{
	
	// TODO comment
	private String name = null;
	private String partClass = null;
	private String partName  = null;
	private String eventClass = null;
	private String eventName  = null;
	private String value = null;
	
	// TODO onderzoeken
	private Object subprop = null;
	
	// TODO comment
	public final static String IAM 			= "property";
	public final static String NAME        	= "name";
	public final static String PART_NAME   	= "part-name";
	public final static String PART_CLASS  	= "part-class";
	public final static String EVENT_NAME   = "event-name";
	public final static String EVENT_CLASS  = "event-class";
	
	/**
	 * 
	 * @param node
	 */
	public Property(Element node) {
		super(node);		
		process();
	}

	public void process() {
		
		processAttributes();
			
		NodeList childItems = node.getChildNodes();

		if(childItems != null) {		
			
			for(int i=0; i<childItems.getLength(); ++i) {
				Node child = childItems.item(i);	
				if(child.getNodeType() == Node.ELEMENT_NODE)
					processElement((Element)child);
			}
			
			if(subprop == null && childItems.getLength() == 1)
				setValue(node.getFirstChild().getNodeValue());
		}	
	}
	
	/**
	 * 
	 */
	@Override
	public void processElement(Element elem) {
		// TODO Auto-generated method stub
		
		if(elem.getTagName().equals(Property.IAM))
			setSubprop(new Property(elem));
		else if(elem.getTagName().equals(Constant.IAM))
			setSubprop(new Constant(elem));
		else if(elem.getTagName().equals(Reference.IAM))
			setSubprop(new Reference(elem));
		else if(elem.getTagName().equals(Call.IAM))
			setSubprop(new Call(elem));	
	}
	
	/**
	 * 
	 */
	public void processAttributes() {
		super.processAttributes();
		
		NamedNodeMap attributes = node.getAttributes();
		
		if(attributes != null) {
			if(attributes.getNamedItem(NAME) != null)
				setName(attributes.getNamedItem(NAME).getNodeValue());
			if(attributes.getNamedItem(PART_NAME) != null)
				setPartName(attributes.getNamedItem(PART_NAME).getNodeValue());
			if(attributes.getNamedItem(PART_CLASS) != null)
				setPartClass(attributes.getNamedItem(PART_CLASS).getNodeValue());
			if(attributes.getNamedItem(EVENT_CLASS) != null)
				setEventClass(attributes.getNamedItem(EVENT_CLASS).getNodeValue());
			if(attributes.getNamedItem(EVENT_NAME) != null)
				setEventName(attributes.getNamedItem(EVENT_NAME).getNodeValue());
		}
	}
	
	/**
	 * 
	 * @param property
	 */
	public void executeProperty(View invoker, Part subTree, Vocabulary voc) {

		
		if(subprop != null) {	
			if(subprop.getClass() == Property.class)
				executeNestedProperty(invoker, subTree, voc);
			else if(subprop.getClass() == Call.class)
				executeNestedCall(invoker, subTree, voc);
		}
		else {
			View root = invoker.getRootView();
			View element = root.findViewWithTag(partName);
			Part invokingPart = subTree.searchPart(partName);
			
			RenderUtils.applyProperty((Object)element, invokingPart, this, "setMethod", voc);
		}
	}
	
	/**
	 * 
	 * @param invoker
	 * @param subTree
	 * @param voc
	 */
	private void executeNestedCall(View invoker, Part subTree, Vocabulary voc) {
		
		View root = invoker.getRootView();
		Call subProp = (Call)subprop;
		
		// Execute call
		Object getValue = ((Call)subProp).execute(invoker, subTree, voc);
		
		// Haal de juiste views op
		View propView = root.findViewWithTag(partName);
		
		// Haal de juiste parts op
		Part propPart = subTree.searchPart(partName);
		
		// Apply the object on the parent <property>
		RenderUtils.applyPropertyWithGivenObjectArray((Object)propView, propPart, this, new Object[] {getValue}, "setMethod", voc);	
	}
	
	/**
	 * 
	 * @param prop
	 * @param subProp
	 */
	private void executeNestedProperty(View invoker, Part subTree, Vocabulary voc) {
		View root = invoker.getRootView();
	
		// Haal de juiste views op
		View propView = root.findViewWithTag(partName);
		
		// Haal de juiste parts op
		Part propPart = subTree.searchPart(partName);
		
		// Haal de waarde van de geneste property op
		Object getValue = ((Property)subprop).executeGetProperty(invoker, subTree, voc);
		
		// Apply the object on the parent <property>
		RenderUtils.applyPropertyWithGivenObjectArray((Object)propView, propPart, this, new Object[] {getValue}, "setMethod", voc);
	}
	
	public Object executeGetProperty(View invoker, Part subTree, Vocabulary voc) {
		View root = invoker.getRootView();

		// Haal de juiste views op
		View propView = root.findViewWithTag(partName);
		
		// Haal de juiste parts op
		Part propPart = subTree.searchPart(partName);
		
		// Haal de waarde van de geneste property op
		return RenderUtils.applyProperty((Object)propView, propPart, this, "getMethod", voc);
	}

	/**
	 * 
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 
	 * @return
	 */
	public String getName() {
		return name;
	}

	/**
	 * 
	 * @param className
	 */
	public void setPartClass(String className) {
		this.partClass = className;
	}

	/**
	 * 
	 * @return
	 */
	public String getPartClass() {
		return partClass;
	}

	/**
	 * 
	 * @param partName
	 */
	public void setPartName(String partName) {
		this.partName = partName;
	}

	/**
	 * 
	 * @return
	 */
	public String getPartName() {
		return partName;
	}

	/**
	 * 
	 * @param m_subprop
	 */
	public void setSubprop(Object m_subprop) {
		this.subprop = m_subprop;
	}

	/**
	 * 
	 * @return
	 */
	public Object getSubprop() {
		return subprop;
	}

	/**
	 * @param eventClass the event_class to set
	 */
	public void setEventClass(String eventClass) {
		this.eventClass = eventClass;
	}

	/**
	 * @return the event_class
	 */
	public String getEventClass() {
		return eventClass;
	}

	/**
	 * @param eventName the event_name to set
	 */
	public void setEventName(String eventName) {
		this.eventName = eventName;
	}

	/**
	 * @return the event_name
	 */
	public String getEventName() {
		return eventName;
	}

	/**
	 * @param value the value to set
	 */
	public void setValue(String value) {
		this.value = value;
	}

	/**
	 * @return the value
	 */
	public String getValue() {
		return value;
	}

}
